from PIL import Image, ImageDraw
'''
1.浮点算法
Gray=R*0.3+G*0.59+B*0.11
2.整数方法
Gray=(R*30+G*59+B*11)/100
3.移位方法
Gray =(R*76+G*151+B*28)>>8
4.平均值法
Gray=(R+G+B)/3
5.仅取绿色
Gray=G
将原来的RGB(R,G,B)中的R,G,B统一用Gray替换，形成新的颜色RGB(Gray,Gray,Gray)，用它替换原来的RGB(R,G,B)就是灰度图了。
'''
# todo 彩色图片转换成灰度图
# 打开原始图片
# im = Image.open('vc.png')
# # 展示原始图片
# # im.show()
# # 将原始图片灰度化
# grey_im = im.convert('L')
# # 展示灰度化图片
# grey_im.show()
# # 保存灰度化图片
# grey_im.save('gray.png')

# todo 将灰度图片二值化
'''
所谓二值化就是将灰度图像转换成由黑白二色组成的图像。思路就是确定一个阈值，大于阈值的像素表示为白色，小于阈值的像素表示为黑色，
以此将图片的像素（灰度值）划分为两部分：0和1，例如0代表黑色，1代表白色，然后我们就可以用一串0和1组成的数字来表示一张图片
'''
# 二值处理
# 设定阈值threshold，像素值小于阈值，取值0，像素值大于阈值，取值1
# 阈值具体多少需要多次尝试，不同阈值效果不一样
# def get_table(threshold=115):
#     table = []
#     for i in range(256):
#         if i < threshold:
#             table.append(0)
#         else:
#             table.append(1)
#     return table
#
# # 打开灰度化图片并进行二值处理
# binary_im = Image.open('gray.png').point(get_table(150), "1")
# # 展示二值化图片
# binary_im.show()
# # 保存二值化图片
# binary_im.save('binary.png')

# todo 对图片进行降噪处理
'''
我们看二值化后的图片，可以看到还有一些干扰线，这些线条也会影响算法的识别准确率，所以我们需要想办法去掉这些干扰线。

降噪的方法有很多，主要难点是判断哪些点是噪点。由于我们这张验证码图片上的数字和字母的线条比干扰线的线条粗，
因此我们认为字母和数字线条上的点周围8个点范围内黑色点的个数应该比干扰线上的点要多。因此我们这里采用的思路是：

根据一个点 A 的 RGB 值，与周围的8个点的 RGB 值比较，设定一个值 N（0 <N <8），当 A 的 RGB 值与周围8个点的 RGB 相等数小于 N 时，此点为噪点。
'''
# 判断噪点,如果确认是噪点,用该点的上面一个点的灰度进行替换
# 根据一个点A的RGB值，与周围的8个点的RBG值比较，设定一个值 N（0 <N <8），当A的RGB值与周围8个点的RGB相等数小于N时，此点为噪点
# x, y: 像素点坐标
# G: 图像二值化阀值
# N: 降噪率 0 < N <8
def get_pixel(image, x, y, G, N):
    # 获取像素值
    L = image.getpixel((x, y))

    # 与阈值比较
    if L > G:
        L = True
    else:
        L = False

    nearDots = 0

    if L == (image.getpixel((x - 1, y - 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x - 1, y)) > G):
        nearDots += 1
    if L == (image.getpixel((x - 1, y + 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x, y - 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x, y + 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x + 1, y - 1)) > G):
        nearDots += 1
    if L == (image.getpixel((x + 1, y)) > G):
        nearDots += 1
    if L == (image.getpixel((x + 1, y + 1)) > G):
        nearDots += 1

    if nearDots < N:
        return image.getpixel((x, y - 1))
    else:
        return None


# 降噪
# Z: 降噪次数
def clear_noise(image, G,N , Z):
    draw = ImageDraw.Draw(image)

    for i in range(0, Z):
        for x in range(1, image.size[0] - 1):
            for y in range(1, image.size[1] - 1):
                color = get_pixel(image, x, y, G, N)
                if color is not None:
                    draw.point((x, y), color)

# 打开二值化图片
b_im = Image.open('binary.png')
# 将二值化图片降噪
clear_noise(b_im, 50, 4, 20)
# 展示降噪后的图片
b_im.show()
# 保存降噪后的图片
b_im.save('result.png')